#include "stm32f10x.h"                  // 引入STM32F10x系列微控制器的头文件
#include "Delay.h"                      // 引入延时函数的头文件
#include "LED.h"                        // 引入LED控制的头文件
#include "Key.h"                        // 引入按键控制的头文件
#include "OLED.h"                       // 引入OLED显示的头文件
#include "Motor.h"                      // 引入电机控制的头文件
#include "Servo.h"                      // 引入舵机控制的头文件
#include "Encoder.h"                    // 引入编码器的头文件
#include "Ctrl.h"                       // 引入控制函数的头文件
#include "PID.h"                        // 引入PID控制的头文件
#include "Timer.h"                      // 引入定时器的头文件

uint8_t KeyNum;                         // 按键编号
uint16_t num;                           // 通用数字变量

extern PID_t MPID;                      // 引入外部的PID控制结构体

#define		RST		0                    // 定义复位动作
#define		C1		11                   // 定义C1动作
#define		C2		12                   // 定义C2动作
#define		C3		13                   // 定义C3动作
#define		SU		21                   // 定义SU动作
#define		SM		22                   // 定义SM动作
#define		SD		23                   // 定义SD动作

uint8_t StartFlag;                      // 开始标志
uint8_t State;                          // 状态变量
uint16_t Time[]  = {100,100,500,500,100,1200,500,100,500,500}; // 时间数组
uint8_t Action[] = {RST,C1, SM, SU, C2, SM,  SU, C3, SD, SU}; // 动作数组

uint8_t UpParam = 90, MiddleParam = 65, DownParam = 60; // 上中下参数

int main(void)
{
	LED_Init();                       // 初始化LED
	Key_Init();                       // 初始化按键
	OLED_Init();                      // 初始化OLED显示
	Servo_Init();                     // 初始化舵机
	Ctrl_Init();                      // 初始化控制函数
	Timer_Init();                     // 初始化定时器
	
	OLED_ShowString(1, 1, "Target:"); // OLED显示目标值
	OLED_ShowString(2, 1, "Real  :"); // OLED显示实际值
	OLED_ShowString(3, 1, "Out   :"); // OLED显示输出值
	OLED_ShowString(4, 1, "U:00 M:00 D:00"); // OLED显示上中下参数
	
	while (1)                         // 主循环
	{
		KeyNum = Key_GetNum();         // 获取按键编号
		if (KeyNum == 1)               // 如果按键1被按下
		{
			StartFlag = !StartFlag;    // 切换开始标志
			if (StartFlag == 1)        // 如果开始标志为1
			{
				LED_ON();              // 打开LED
			}
			else                        // 否则
			{
				LED_OFF();             // 关闭LED
			}
		}
		if (KeyNum == 2)               // 如果按键2被按下
		{
			MiddleParam += 1;          // 中参数加1
		}
		if (KeyNum == 3)               // 如果按键3被按下
		{
			MiddleParam -= 1;          // 中参数减1
		}
		OLED_ShowSignedNum(1, 8, MPID.Target, 5); // OLED显示目标值
		OLED_ShowSignedNum(2, 8, MPID.Real, 5);   // OLED显示实际值
		OLED_ShowSignedNum(3, 8, MPID.Out, 5);    // OLED显示输出值
		OLED_ShowNum(4, 3, UpParam, 2);           // OLED显示上参数
		OLED_ShowNum(4, 8, MiddleParam, 2);       // OLED显示中参数
		OLED_ShowNum(4, 13, DownParam, 2);        // OLED显示下参数
	}
}

void DoAction(uint8_t Action)          // 执行动作函数
{
	if (Action == RST)                 // 如果动作是复位
	{
		Ctrl_Reset();                   // 执行复位控制
	}
	else if(Action == C1)              // 如果动作是C1
	{
		Ctrl_SetTarget(60);            // 设置目标值为60
	}
	else if(Action == C2)              // 如果动作是C2
	{
		Ctrl_SetTarget(3200);          // 设置目标值为3200
	}
	else if(Action == C3)              // 如果动作是C3
	{
		Ctrl_SetTarget(3330);          // 设置目标值为3330
	}
	else if(Action == SU)              // 如果动作是SU
	{
		Servo_SetAngle(UpParam);       // 设置舵机角度为上参数
	}
	else if(Action == SM)              // 如果动作是SM
	{
		Servo_SetAngle(MiddleParam);   // 设置舵机角度为中参数
	}
	else if(Action == SD)              // 如果动作是SD
	{
		Servo_SetAngle(DownParam);     // 设置舵机角度为下参数
	}
}

void TIM4_IRQHandler(void)            // 定时器4中断处理函数
{
	static uint16_t TCount[2];         // 静态计数数组
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET) // 如果定时器4更新中断标志位被设置
	{
		TCount[0] ++;                  // 计数器0加1
		if (TCount[0] >= 50)           // 如果计数器0大于等于50
		{
			TCount[0] = 0;             // 计数器0清零
			Ctrl_Loop();               // 执行控制循环
		}
		
		if (StartFlag)                 // 如果开始标志为真
		{
			TCount[1] ++;              // 计数器1加1
			if (TCount[1] >= Time[State]) // 如果计数器1大于等于当前状态的时间
			{
				TCount[1] = 0;         // 计数器1清零
				DoAction(Action[State]); // 执行当前状态的动作
				State ++;               // 状态加1
				State %= 10;            // 状态取模10
			}
		}
		
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update); // 清除定时器4更新中断标志位
	}
}